package com.education.ai.service.impl;

import com.education.ai.dao.TeacherDao;
import com.education.ai.dao.StudentDao;
import com.education.ai.dao.AdminDao;
import com.education.ai.context.AdminContext;
import com.education.ai.entity.Teacher;
import com.education.ai.entity.Student;
import com.education.ai.entity.Admin;
import com.education.ai.exception.BusinessException;
import com.education.ai.model.dto.LoginRequest;
import com.education.ai.model.dto.LoginResponse;
import com.education.ai.model.dto.ChangePasswordRequest;
import com.education.ai.model.dto.RegisterRequest;
import com.education.ai.model.dto.TeacherResponse;
import com.education.ai.model.dto.UserResponse;
import com.education.ai.model.dto.StudentResponse;
import com.education.ai.service.AuthService;
import com.education.ai.util.JwtUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.Date;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;

/**
 * 认证服务实现类
 */
@Service
public class AuthServiceImpl implements AuthService {

    private static final Logger logger = LoggerFactory.getLogger(AuthServiceImpl.class);

    // JWT密钥
    @Value("${jwt.secret:defaultSecret}")
    private String jwtSecret;
    
    // JWT过期时间（12小时）
    @Value("${jwt.expiration:43200000}")
    private long jwtExpiration;
    
    // 教师令牌过期时间（小时）
    @Value("${jwt.teacher.expiration.hours:24}")
    private int teacherTokenExpirationHours;
    
    // 学生令牌过期时间（小时）
    @Value("${jwt.student.expiration.hours:12}")
    private int studentTokenExpirationHours;
    
    @Autowired
    private TeacherDao teacherDao;
    
    @Autowired(required = false)
    private StudentDao studentDao;
    
    @Autowired(required = false)
    private AdminDao adminDao;
    
    // 存储已登录的会话
    private static final Map<String, String> activeTokens = new ConcurrentHashMap<>();
    
    @Override
    @Transactional
    public TeacherResponse registerTeacher(RegisterRequest registerRequest) {
        try {
            logger.info("开始教师注册流程 - 姓名: {}, 工号: {}", registerRequest.getName(), registerRequest.getUserId());
            
            // 验证两次密码是否一致
            if (!registerRequest.getPassword().equals(registerRequest.getConfirmPassword())) {
                logger.warn("教师注册失败 - 两次密码不一致 - 姓名: {}", registerRequest.getName());
                throw new BusinessException("两次输入的密码不一致");
            }
            
            // 验证工号是否已存在
            Optional<Teacher> existingTeacher = teacherDao.findByTeacherId(registerRequest.getUserId());
            if (existingTeacher.isPresent()) {
                logger.warn("教师注册失败 - 工号已存在 - 工号: {}", registerRequest.getUserId());
                throw new BusinessException("该工号已被注册");
            }

            // 验证手机号是否已存在
            if (registerRequest.getPhone() != null && !registerRequest.getPhone().isEmpty()) {
                    List<Teacher> teachers = teacherDao.findAll().stream()
                            .filter(t -> registerRequest.getPhone().equals(t.getPhone()))
                            .collect(Collectors.toList());
                if (!teachers.isEmpty()) {
                    logger.warn("教师注册失败 - 手机号已存在 - 手机号: {}", registerRequest.getPhone());
                        throw new BusinessException("该手机号已被注册");
                    }
            }

            // 创建教师对象
            Teacher teacher = new Teacher();
            teacher.setTeacherId(registerRequest.getUserId());
            teacher.setName(registerRequest.getName());
            teacher.setPassword(registerRequest.getPassword());
            teacher.setPhone(registerRequest.getPhone());
            teacher.setEmail(registerRequest.getEmail());
            teacher.setSubject(registerRequest.getSubject());
            teacher.setProfile(registerRequest.getProfile());
            teacher.setStatus(1); // 1表示正常状态
            teacher.setCreateTime(LocalDateTime.now());
            
            // 保存教师信息
            teacherDao.save(teacher);

            // 构建返回对象
            TeacherResponse response = new TeacherResponse();
            BeanUtils.copyProperties(teacher, response);

            logger.info("教师注册成功 - 工号: {}, 姓名: {}", teacher.getTeacherId(), teacher.getName());
                
                return response;
        } catch (BusinessException be) {
            throw be;
        } catch (Exception e) {
            logger.error("教师注册失败 - 系统异常: {}", e.getMessage(), e);
            throw new BusinessException("注册失败: " + e.getMessage());
        }
    }
    
    @Override
    @Transactional
    public StudentResponse registerStudent(RegisterRequest registerRequest) {
        try {
            logger.info("开始学生注册流程 - 姓名: {}, 学号: {}", registerRequest.getName(), registerRequest.getUserId());
            
            // 验证两次密码是否一致
            if (!registerRequest.getPassword().equals(registerRequest.getConfirmPassword())) {
                logger.warn("学生注册失败 - 两次密码不一致 - 姓名: {}", registerRequest.getName());
                throw new BusinessException("两次输入的密码不一致");
            }
            
            // 验证学号是否已存在
            Optional<Student> existingStudent = studentDao.findByStudentId(registerRequest.getUserId());
            if (existingStudent.isPresent()) {
                logger.warn("学生注册失败 - 学号已存在 - 学号: {}", registerRequest.getUserId());
                throw new BusinessException("该学号已被注册");
            }

            // 验证手机号是否已存在
            if (registerRequest.getPhone() != null && !registerRequest.getPhone().isEmpty()) {
                List<Student> students = studentDao.findAll().stream()
                        .filter(s -> registerRequest.getPhone().equals(s.getPhone()))
                        .collect(Collectors.toList());
                if (!students.isEmpty()) {
                    logger.warn("学生注册失败 - 手机号已存在 - 手机号: {}", registerRequest.getPhone());
                    throw new BusinessException("该手机号已被注册");
                }
            }

            // 验证班级是否选择
            if (registerRequest.getClassName() == null || registerRequest.getClassName().isEmpty()) {
                logger.warn("学生注册失败 - 未选择班级 - 姓名: {}", registerRequest.getName());
                throw new BusinessException("请选择班级");
            }

            // 创建学生对象
            Student student = new Student();
            student.setStudentId(registerRequest.getUserId());
            student.setName(registerRequest.getName());
            student.setPassword(registerRequest.getPassword());
            student.setPhone(registerRequest.getPhone());
            student.setEmail(registerRequest.getEmail());
            student.setClassName(registerRequest.getClassName());
            student.setStatus(1); // 1表示正常状态
            student.setCreateTime(LocalDateTime.now());
            
            // 保存学生信息
            studentDao.save(student);

            // 构建返回对象
            StudentResponse response = new StudentResponse();
            BeanUtils.copyProperties(student, response);

            logger.info("学生注册成功 - 学号: {}, 姓名: {}, 班级: {}",
                    student.getStudentId(), student.getName(), student.getClassName());
                
                return response;
        } catch (BusinessException be) {
            throw be;
        } catch (Exception e) {
            logger.error("学生注册失败 - 系统异常: {}", e.getMessage(), e);
            throw new BusinessException("注册失败: " + e.getMessage());
        }
    }
    
    @Override
    public UserResponse login(LoginRequest loginRequest) {
        try {
            // 根据用户角色选择不同的登录逻辑
            if (loginRequest.getUserRole() == null || loginRequest.getUserRole() == 1) {
                // 教师登录
                return loginTeacher(loginRequest);
            } else if (loginRequest.getUserRole() == 2) {
                // 学生登录
                return loginStudent(loginRequest);
            } else if (loginRequest.getUserRole() == 3) {
                // 管理员登录
                return loginAdmin(loginRequest);
            } else {
                logger.warn("登录失败 - 不支持的用户角色: {}", loginRequest.getUserRole());
                throw new BusinessException("不支持的用户角色");
            }
        } catch (BusinessException be) {
            // 业务异常直接抛出
            throw be;
        } catch (Exception e) {
            logger.error("登录失败 - 系统异常: {}", e.getMessage(), e);
            throw new BusinessException("登录失败: " + e.getMessage());
        }
    }
    
    /**
     * 教师登录
     */
    private UserResponse loginTeacher(LoginRequest loginRequest) {
        Teacher teacher = null;
        
        // 根据登录类型选择不同的登录方式
        if (loginRequest.getLoginType() == 1) {
            // 工号登录
            Optional<Teacher> teacherOpt = teacherDao.findByTeacherId(loginRequest.getLoginId());
            if (!teacherOpt.isPresent()) {
                logger.warn("登录失败 - 教师工号不存在: {}", loginRequest.getLoginId());
                throw new BusinessException("工号不存在");
            }
            teacher = teacherOpt.get();
        } else if (loginRequest.getLoginType() == 2) {
            // 手机号登录
            List<Teacher> teachers = teacherDao.findAll().stream()
                    .filter(t -> loginRequest.getLoginId().equals(t.getPhone()))
                    .collect(Collectors.toList());
            if (teachers.isEmpty()) {
                logger.warn("登录失败 - 教师手机号不存在: {}", loginRequest.getLoginId());
                throw new BusinessException("手机号不存在");
            }
                teacher = teachers.get(0);
        } else {
            logger.warn("登录失败 - 不支持的登录类型: {}", loginRequest.getLoginType());
            throw new BusinessException("不支持的登录类型");
        }
        
        // 检查教师状态
        if (teacher.getStatus() != null && teacher.getStatus() == 0) {
            logger.warn("登录失败 - 账号已禁用: {}", teacher.getTeacherId());
            throw new BusinessException("账号已被禁用，请联系管理员");
        }
        
        // 校验密码
        if (!loginRequest.getPassword().equals(teacher.getPassword())) {
            logger.warn("登录失败 - 密码错误: {}", teacher.getTeacherId());
            throw new BusinessException("密码错误");
        }
        
        // 更新最后登录时间
        updateTeacherLastLoginTime(teacher);
        
        // 记录登录成功
        logger.info("教师登录成功 - 工号: {}, 姓名: {}, 登录类型: {}", 
                teacher.getTeacherId(), teacher.getName(), 
                loginRequest.getLoginType() == 1 ? "工号登录" : "手机号登录");
        
        // 返回通用用户信息
        return UserResponse.builder()
                .userId(teacher.getTeacherId())
                .name(teacher.getName())
                .email(teacher.getEmail())
                .phone(teacher.getPhone())
                .status(teacher.getStatus())
                .userRole(1) // 1表示教师
                .subject(teacher.getSubject())
                .lastLoginTime(teacher.getLastLoginTime() != null ? teacher.getLastLoginTime().toString() : null)
                .build();
    }
    
    /**
     * 学生登录
     */
    private UserResponse loginStudent(LoginRequest loginRequest) {
        Student student = null;
        
        // 根据登录类型选择不同的登录方式
        if (loginRequest.getLoginType() == 1) {
            // 学号登录
            Optional<Student> studentOpt = studentDao.findByStudentId(loginRequest.getLoginId());
            if (!studentOpt.isPresent()) {
                logger.warn("登录失败 - 学生学号不存在: {}", loginRequest.getLoginId());
                throw new BusinessException("学号不存在");
            }
            student = studentOpt.get();
        } else if (loginRequest.getLoginType() == 2) {
            // 手机号登录
            List<Student> students = studentDao.findAll().stream()
                    .filter(s -> loginRequest.getLoginId().equals(s.getPhone()))
                    .collect(Collectors.toList());
            if (students.isEmpty()) {
                logger.warn("登录失败 - 学生手机号不存在: {}", loginRequest.getLoginId());
                throw new BusinessException("手机号不存在");
            }
            student = students.get(0);
        } else {
            logger.warn("登录失败 - 不支持的登录类型: {}", loginRequest.getLoginType());
            throw new BusinessException("不支持的登录类型");
        }

            // 检查学生状态
            if (student.getStatus() != null && student.getStatus() == 0) {
                logger.warn("登录失败 - 账号已禁用: {}", student.getStudentId());
                throw new BusinessException("账号已被禁用，请联系管理员");
            }
            
        // 校验密码
            if (!loginRequest.getPassword().equals(student.getPassword())) {
                logger.warn("登录失败 - 密码错误: {}", student.getStudentId());
                throw new BusinessException("密码错误");
            }
            
            // 更新最后登录时间
            updateStudentLastLoginTime(student);
            
        // 记录登录成功
        logger.info("学生登录成功 - 学号: {}, 姓名: {}, 登录类型: {}",
                student.getStudentId(), student.getName(),
                loginRequest.getLoginType() == 1 ? "学号登录" : "手机号登录");

            // 返回通用用户信息
        return UserResponse.builder()
                    .userId(student.getStudentId())
                    .name(student.getName())
                    .email(student.getEmail())
                    .phone(student.getPhone())
                    .status(student.getStatus())
                    .className(student.getClassName())
                    .grade(student.getGrade())
                    .userRole(2) // 2表示学生
                    .lastLoginTime(student.getLastLoginTime() != null ? student.getLastLoginTime().toString() : null)
                    .build();
    }
    
    /**
     * 管理员登录
     */
    private UserResponse loginAdmin(LoginRequest loginRequest) {
        // 实现管理员登录逻辑
        logger.info("尝试管理员登录: {}", loginRequest.getLoginId());
        
        if (adminDao == null) {
            logger.error("AdminDao未注入，无法完成管理员登录");
            throw new BusinessException("系统未配置管理员登录功能");
        }
        
        try {
            Optional<Admin> adminOpt = adminDao.findByAdminId(loginRequest.getLoginId());
            if (!adminOpt.isPresent()) {
                logger.warn("登录失败 - 管理员ID不存在: {}", loginRequest.getLoginId());
                throw new BusinessException("管理员ID不存在");
            }
            
            Admin admin = adminOpt.get();
            
            // 检查管理员状态
            if (admin.getStatus() != null && admin.getStatus() == 0) {
                logger.warn("登录失败 - 账号已禁用: {}", admin.getAdminId());
                throw new BusinessException("账号已被禁用，请联系系统管理员");
            }
            
            // 校验密码 - 简单比较
            if (!loginRequest.getPassword().equals(admin.getPassword())) {
                logger.warn("登录失败 - 密码错误: {}", admin.getAdminId());
                throw new BusinessException("密码错误");
            }
            
            // 更新最后登录时间
            admin.setLastLoginTime(LocalDateTime.now());
            adminDao.update(admin);
            
            // 设置管理员上下文
            AdminContext.setCurrentAdmin(admin);
            
            logger.info("管理员登录成功 - ID: {}, 姓名: {}", admin.getAdminId(), admin.getName());
            
            // 返回通用用户信息
            UserResponse response = UserResponse.builder()
                    .userId(admin.getAdminId())
                    .name(admin.getName())
                    .email(admin.getEmail())
                    .phone(admin.getPhone())
                    .status(admin.getStatus())
                    .userRole(3) // 3表示管理员
                    .lastLoginTime(admin.getLastLoginTime() != null ? admin.getLastLoginTime().toString() : null)
                    .build();
            
            return response;
        } catch (BusinessException be) {
            throw be;
        } catch (Exception e) {
            logger.error("管理员登录失败 - ID: {}, 错误: {}", loginRequest.getLoginId(), e.getMessage(), e);
            throw new BusinessException("登录失败: " + e.getMessage());
        }
    }
    
    @Override
    public TeacherResponse getTeacherById(String teacherId) {
        Optional<Teacher> teacherOpt = teacherDao.findByTeacherId(teacherId);
        if (!teacherOpt.isPresent()) {
            throw new BusinessException("教师工号不存在");
        }
        
        Teacher teacher = teacherOpt.get();
        TeacherResponse response = new TeacherResponse();
        BeanUtils.copyProperties(teacher, response);
        
        return response;
    }
    
    @Override
    public String generateToken(String userId, Integer userRole) {
        Date now = new Date();
        Date expiryDate = new Date(now.getTime() + jwtExpiration);
        
        // 在JWT中添加用户角色信息
        String token = Jwts.builder()
                .setSubject(userId)
                .claim("role", userRole)
                .setIssuedAt(now)
                .setExpiration(expiryDate)
                .signWith(SignatureAlgorithm.HS512, jwtSecret)
                .compact();
        
        // 保存令牌
        activeTokens.put(userId, token);
        
        return token;
    }
    
    @Override
    public String getUserIdFromToken(String token) {
        if (token == null) {
            return null;
        }
        
        // 处理Bearer前缀
        if (token.startsWith("Bearer ")) {
        token = token.substring(7);
        }
        
        try {
            Claims claims = Jwts.parser()
                    .setSigningKey(jwtSecret)
                    .parseClaimsJws(token)
                    .getBody();
            
            String userId = claims.getSubject();
            
            // 检查token是否仍然有效
            String activeToken = activeTokens.get(userId);
            if (activeToken == null || !activeToken.equals(token)) {
                logger.warn("Token已失效或被登出 - userId: {}", userId);
                return null;
            }
            
            return userId;
        } catch (Exception e) {
            logger.error("解析Token失败: {}", e.getMessage());
            return null;
        }
    }
    
    @Override
    public Integer getUserRoleFromToken(String token) {
        if (token == null) {
            return null;
        }
        
        // 处理Bearer前缀
        if (token.startsWith("Bearer ")) {
            token = token.substring(7);
        }
        
        try {
            Claims claims = Jwts.parser()
                    .setSigningKey(jwtSecret)
                    .parseClaimsJws(token)
                    .getBody();
            
            // 从claims中获取角色信息
            return claims.get("role", Integer.class);
        } catch (Exception e) {
            logger.error("解析Token角色失败: {}", e.getMessage());
            return null;
        }
    }
    
    @Override
    public void logout(String userId) {
        logger.info("用户登出 - userId: {}", userId);
        activeTokens.remove(userId);
    }
    
    /**
     * 更新教师最后登录时间
     */
    @Transactional
    public void updateTeacherLastLoginTime(Teacher teacher) {
        teacher.setLastLoginTime(LocalDateTime.now());
        teacherDao.update(teacher);
    }
    
    /**
     * 更新学生最后登录时间
     */
    @Transactional
    public void updateStudentLastLoginTime(Student student) {
        student.setLastLoginTime(LocalDateTime.now());
        // 增加登录次数
        if (student.getLoginCount() == null) {
            student.setLoginCount(1);
        } else {
            student.setLoginCount(student.getLoginCount() + 1);
        }
        if (studentDao != null) {
            studentDao.update(student);
        }
    }
    
    @Override
    public String generateTeacherId() {
        // 生成8位数字工号
        ThreadLocalRandom random = ThreadLocalRandom.current();
        String teacherId;
        boolean exists;
        
        do {
            // 生成8位数字ID
            teacherId = String.format("%08d", random.nextInt(10000000, 100000000));
            // 检查是否已存在
            exists = teacherDao.findByTeacherId(teacherId).isPresent();
        } while (exists);
        
        return teacherId;
    }
    
    @Override
    public String generateStudentId() {
        // 生成8位数字学号
        ThreadLocalRandom random = ThreadLocalRandom.current();
        String studentId;
        boolean exists;
        
        do {
            // 生成8位数字ID，以"202"开头表示是学生
            studentId = String.format("202%05d", random.nextInt(0, 100000));
            // 检查是否已存在
            exists = studentDao != null && studentDao.findByStudentId(studentId).isPresent();
        } while (exists);
        
        return studentId;
    }

    @Override
    @Transactional
    public void changePassword(String userId, ChangePasswordRequest request) {
        logger.info("开始处理用户[{}]的密码修改请求", userId);
        
        if (request.getUserRole() == null || request.getUserRole() == 1) {
            // 教师密码修改
            changeTeacherPassword(userId, request);
        } else if (request.getUserRole() == 2) {
            // 学生密码修改
            changeStudentPassword(userId, request);
        } else if (request.getUserRole() == 3) {
            // 管理员密码修改
            changeAdminPassword(userId, request);
        } else {
            throw new BusinessException("不支持的用户角色类型");
        }
    }
    
    /**
     * 修改教师密码
     */
    private void changeTeacherPassword(String teacherId, ChangePasswordRequest request) {
        // 根据教师ID查询教师
        Optional<Teacher> teacherOpt = teacherDao.findByTeacherId(teacherId);
        if (!teacherOpt.isPresent()) {
            logger.warn("修改密码失败 - 教师不存在: {}", teacherId);
            throw new BusinessException("教师不存在");
        }
        
        Teacher teacher = teacherOpt.get();
        
        // 验证旧密码是否正确(简单比较)
        if (!request.getOldPassword().equals(teacher.getPassword())) {
            logger.warn("修改密码失败 - 原密码错误: {}", teacherId);
            throw new BusinessException("原密码错误");
        }
        
        // 设置新密码
        teacher.setPassword(request.getNewPassword());
        teacher.setUpdateTime(LocalDateTime.now());
        
        try {
            // 保存更新
            teacherDao.update(teacher);
            logger.info("教师[{}]密码修改成功", teacherId);
        } catch (Exception e) {
            logger.error("修改密码失败 - 系统异常: {}", e.getMessage(), e);
            throw new BusinessException("修改密码失败: " + e.getMessage());
        }
    }
    
    /**
     * 修改学生密码
     */
    private void changeStudentPassword(String studentId, ChangePasswordRequest request) {
        // TODO: 实现学生密码修改逻辑
        logger.warn("学生密码修改功能尚未实现");
        throw new BusinessException("学生密码修改功能尚未实现");
    }

    /**
     * 修改管理员密码
     */
    private void changeAdminPassword(String adminId, ChangePasswordRequest request) {
        // TODO: 实现管理员密码修改逻辑
        logger.warn("管理员密码修改功能尚未实现");
        throw new BusinessException("管理员密码修改功能尚未实现");
    }

    @Override
    public TeacherResponse findTeacherByName(String name) {
        logger.info("通过姓名查找教师: {}", name);
        
        // 获取所有教师然后筛选
        List<Teacher> teachers = teacherDao.findAll().stream()
                .filter(t -> t.getName() != null && t.getName().equals(name))
                .collect(Collectors.toList());
                
        if (teachers.isEmpty()) {
            logger.warn("未找到姓名为[{}]的教师", name);
            return null;
        }
        
        Teacher teacher = teachers.get(0);
        TeacherResponse response = new TeacherResponse();
        BeanUtils.copyProperties(teacher, response);
        
        logger.info("找到姓名为[{}]的教师, ID: {}", name, teacher.getId());
        return response;
    }

    /**
     * 验证教师登录
     */
    private LoginResponse validateTeacherLogin(String teacherId, String password) {
        logger.info("尝试教师登录: {}", teacherId);
        
        // 根据教师ID查询教师信息
        Optional<Teacher> optionalTeacher = teacherDao.findByTeacherId(teacherId);
        if (!optionalTeacher.isPresent()) {
            logger.warn("登录失败 - 教师不存在: {}", teacherId);
            throw new BusinessException("教师账号不存在");
        }
        
        Teacher teacher = optionalTeacher.get();
        
        // 简单密码验证(不再使用盐值和加密)
        if (!password.equals(teacher.getPassword())) {
            logger.warn("登录失败 - 密码不正确: {}", teacherId);
            throw new BusinessException("密码不正确");
        }
        
        // 登录成功，更新最后登录时间
        teacher.setLastLoginTime(LocalDateTime.now());
        // 增加登录次数
        if (teacher.getLoginCount() == null) {
            teacher.setLoginCount(1);
        } else {
            teacher.setLoginCount(teacher.getLoginCount() + 1);
        }
        teacherDao.update(teacher);
        
        // 生成JWT Token
        String token = JwtUtil.generateToken(teacher.getTeacherId(), "TEACHER", 
                teacherTokenExpirationHours);
        
        // 构建并返回登录响应
        return LoginResponse.builder()
                .userId(teacher.getTeacherId())
                .name(teacher.getName())
                .token(token)
                .userRole(1) // 1表示教师
                .build();
    }
} 